﻿using System.Collections.Generic;
using System.Collections.Specialized;
using Inovout.Descriptors;
using System;
using System.Linq;

namespace Inovout.NumberGenerator
{
    public class NumberExpression
    {
        private const string prefix = "(";
        private const string suffix = ")";
        private const string separator = ",";
        private List<NumberFunction> numberFunctions;

        public string Statement
        {
            get
            {
                string statement = string.Empty;
                foreach (var numberFunction in numberFunctions)
                {
                    statement += numberFunction.Name;
                    statement += prefix;
                    statement += string.Join(separator, numberFunction.Arguments);
                    statement += suffix;
                }
                return statement;
            }
            set
            {
                Parse(value);
            }
        }
        public void Insert(int index, NumberFunction numberFunction)
        {
            numberFunctions.Insert(index, numberFunction);
        }
        public void Remove(NumberFunction numberFunction)
        {
            numberFunctions.Remove(numberFunction);
        }

        public void Up(NumberFunction numberFunction)
        {
            numberFunctions.Remove(numberFunction);
        }
        public void Down(NumberFunction numberFunction)
        {
            numberFunctions.Remove(numberFunction);
        }

        private List<NumberFunction> Parse(string statement)
        {
            numberFunctions = new List<NumberFunction>();
            string[] numberFunctionArray = statement.Split(new string[] { prefix, suffix }, System.StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < numberFunctionArray.Length; i = i + 2)
            {
                numberFunctions.Add(ComponentRegistry.Resolve<NumberFunction>(numberFunctionArray[i],
                    numberFunctionArray[i + 1].Split(',')));
            }
            return numberFunctions;
        }

        private static NameValueCollection supportedNumberFunctions = new NameValueCollection();
        public static NameValueCollection SupportedNumberFunctions
        {
            get { return new NameValueCollection(supportedNumberFunctions); }
        }

        static NumberExpression()
        {
            RegisterNumberFunction<TextFunction>();
            RegisterNumberFunction<DateFunction>();
            RegisterNumberFunction<TimeFunction>();
            RegisterNumberFunction<SequenceFunction>();
        }
        public static void RegisterNumberFunction<TNumberFunction>() where TNumberFunction : NumberFunction
        {
            Type numberFunctionType = typeof(TNumberFunction);
            string numberFunctionName = numberFunctionType.Name.Substring(0, numberFunctionType.Name.Length - "Function".Length);
            ClassDescriptor classDescriptor = ClassDescriptor.Create(numberFunctionType);
            supportedNumberFunctions.Add(numberFunctionName, classDescriptor.Alias);
            ComponentRegistry.AddComponent(numberFunctionName, typeof(NumberFunction), numberFunctionType);

        }

        public bool Validate()
        {
            return numberFunctions.Exists(numberFunction => numberFunction.GetType().Equals(typeof(SequenceFunction)));
        }
    }
}
